import { forEach, isArray, isEmpty, isFunction, isPlainObject, pick } from 'lodash-es';

/**
 * Types
 */
import type { DeviceManagerType, DevicesType, ResponseType, SubscribeType } from '../typings';

/**
 * 订阅上报事件
 */
function subscribe(this: DeviceManagerType, res: SubscribeType) {
    const { from: id, method, params } = res;

    this.log('上报数据', res);

    // 消息上报
    const isMsg = method === 'onReceive';
    // 定时消息上报
    const isTimer = method === 'onReceiveTimer';
    // 上下线消息上报
    const isOnline = method === 'notify' && params.type === 1003;
    // 电池电量消息上报
    const isBattery = method === 'batteryOnReceive';
    // 网络连接消息上报
    const isNetwork = method === 'networkOnReceive';

    for (const value of this.deviceInstance) {
        let { devices, instance } = value;

        // 判断设备是否为空
        if (isEmpty(devices)) {
            continue;
        }

        // 对象转数组
        if (isPlainObject(devices)) {
            devices = [devices] as DevicesType[];
        }

        // 判定 id 是否匹配
        if ((devices as DevicesType[]).every((device) => device.id !== id)) {
            continue;
        }

        let callbacks = [];

        if (isMsg) callbacks = instance.callbacks;
        if (isTimer) callbacks = instance.timerCallbacks;
        if (isOnline) callbacks = instance.onlineCallbacks;
        if (isBattery) callbacks = instance.batteryCallbacks;
        if (isNetwork) callbacks = instance.networkCallbacks;

        // 判定 callback 是否声明
        if (!callbacks.length) {
            this.log(`设备 ${instance.opts.name} 未监听上报事件`);
        }

        const index = (devices as DevicesType[]).findIndex((device) => device.id === id);

        // 普通消息上报
        if (isMsg) {
            forEach(callbacks, ({ key, callback }) => {
                const payload = isArray(key) && !isEmpty(key) ? pick(params, key) : params;

                if (isFunction(callback) && !isEmpty(payload)) {
                    callback({
                        ...payload,
                        deviceIndex: index,
                        deviceInstance: instance,
                    });
                }
            });

            forEach(instance.conditionCallbacks, ({ condition, callback }) => {
                if (!instance.device.condition || !isFunction(callback)) {
                    return;
                }

                // 如果上报数据 key 的值 !== 监听值
                if (params[condition.key] !== condition.value) {
                    return;
                }

                // 且 and
                if (instance.device.conditionData === 'and') {
                    // 调用对应方法获取其他设备值
                    instance[condition.method]?.(condition.params)?.then?.((arr: ResponseType[]) => {
                        // 如果所有数据 key 的值等于监听值
                        if (arr.every(({ data }) => data === condition.value)) {
                            callback(params);
                        }
                    });
                }

                // 或 or
                if (instance.device.conditionData === 'or') {
                    callback(params);
                }
            });

            break;
        }

        // 上下线消息上报
        if (isOnline) {
            forEach(callbacks, (callback) => {
                callback({
                    ...params.payload,
                    deviceIndex: index,
                    deviceInstance: instance,
                });
            });

            break;
        }

        // 其他消息上报
        forEach(callbacks, (callback) => {
            callback({
                ...params,
                deviceIndex: index,
                deviceInstance: instance,
            });
        });
    }
}

export default subscribe;
